package ija.view.elements;

import ija.model.basis.Desk;
import ija.model.basis.Figure;
import ija.model.figures.Piece;
import ija.model.figures.Queen;
import ija.model.types.FigureColor;
import ija.model.types.FigureRoute;
import ija.model.types.GameMoves;
import ija.view.BoardGameContent;
import ija.xls.notation.DeskCoordinate;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.io.File;
import java.io.IOException;
import java.util.List;

import javax.imageio.ImageIO;
import javax.swing.JPanel;

public class Board extends JPanel implements ActionListener, MouseListener, MouseMotionListener {

    private static final long serialVersionUID = -2396163041233085864L;
    private static final int borderWidth = 15;
    private int dim = 8;
    private BoardGameContent view;
    private Desk BoardDesk;
    protected Image iBackground = null;
    protected Image iBackgroundGray = null;
    protected Image iKingBlack = null;
    protected Image iKingWhite = null;
    protected Image iPieceBlack = null;
    protected Image iPieceWhite = null;
    private Clickable[][] mainClickMap;
    private Clickable[][] tempClickMap;
    private List<GameMoves> gameMoves;

    public static enum ClickableType {
        FIGURE, DESTINATION, HOVER, NOTHING
    }

    // region Constructors
    public Board(int dim, BoardGameContent gc) {
        super(new BorderLayout());
        this.view = gc;
        // BoardDesk = new Desk();
        this.dim = dim;
        try {
            this.iBackground = ImageIO.read(new File("graphic/background.png"));
            this.iBackgroundGray = ImageIO.read(new File("graphic/backgroundGray.png"));
            this.iKingBlack = ImageIO.read(new File("graphic/kingBlack.png"));
            this.iKingWhite = ImageIO.read(new File("graphic/kingWhite.png"));
            this.iPieceBlack = ImageIO.read(new File("graphic/pieceBlack.png"));
            this.iPieceWhite = ImageIO.read(new File("graphic/pieceWhite.png"));
        } catch (IOException e) {
        }
        this.addMouseListener(this);
        this.addMouseMotionListener(this);
        this.mainClickMap = new Clickable[dim][dim];
        this.tempClickMap = new Clickable[dim][dim];
        this.clearMainClickMap();
        this.resetTempClickMap();
    }

    // endregion Constructors
    // region Nested Classes
    private class Clickable {
        ClickableType type;
        String s;

        public Clickable(ClickableType type, String s) {
            this.type = type;
            this.s = s;
        }
    };

    // endregion Nested Classes
    // region ClickMap
    public void clearMainClickMap() {
        for (int i = 0; i < this.dim; i++) {
            for (int j = 0; j < this.dim; j++) {
                this.mainClickMap[i][j] = new Clickable(ClickableType.NOTHING, "");
            }
        }
    }

    public void resetTempClickMap() {
        for (int i = 0; i < this.dim; i++) {
            for (int j = 0; j < this.dim; j++) {
                this.tempClickMap[i][j] = new Clickable(ClickableType.NOTHING, "");
                this.tempClickMap[i][j].type = this.mainClickMap[i][j].type;
                this.tempClickMap[i][j].s = this.mainClickMap[i][j].s;
            }
        }
    }

    public void setMainClickMap(List<GameMoves> gm, DeskCoordinate root, boolean onlyFigures) {
        DeskCoordinate dc, rootdc;
        String s;
        this.clearMainClickMap();
        if ((gm == null) || gm.isEmpty()) {
            return;
        }
        if (!onlyFigures) {
            for (GameMoves move : gm) {

                for (FigureRoute r : move.getPositions()) {
                    dc = r.getCoordinate();
                    s = r.getText();
                    rootdc = move.getPositions().getRoot().getData().getCoordinate();
                    if ((root == null) || (root.equals(rootdc))) {
                        this.mainClickMap[dc.getX()][dc.getY()] = new Clickable(
                                ClickableType.DESTINATION, s);
                    }
                }
            }
        }

        for (GameMoves move : gm) {
            dc = move.getPositions().getRoot().getData().getCoordinate();
            this.mainClickMap[dc.getX()][dc.getY()] = new Clickable(ClickableType.FIGURE, "");
        }
    }

    // endregion ClickMap
    // region Listeners
    @Override
    public void mousePressed(MouseEvent arg0) {
        if (this.isEnabled()) {
        }
    }

    @Override
    public void mouseEntered(MouseEvent arg0) {
        // TODO Auto-generated method stub

    }

    @Override
    public void mouseExited(MouseEvent arg0) {
        // TODO Auto-generated method stub
    }

    @Override
    public void mouseClicked(MouseEvent ev) {

    }

    @Override
    public void mouseReleased(MouseEvent ev) {
        if (this.isEnabled()) {
            DeskCoordinate dc;
            dc = this.decodeClick(ev.getX(), ev.getY());
            switch (this.mainClickMap[dc.getX()][dc.getY()].type) {
            case DESTINATION:
                String s = this.mainClickMap[dc.getX()][dc.getY()].s;
                if (this.view != null) {
                    this.view.tfMove.setText(s);
                    this.clearMainClickMap();
                    this.resetTempClickMap();
                    this.view.bMove.doClick();
                }
                break;
            case FIGURE:
                this.setMainClickMap(this.gameMoves, dc, false);
                this.resetTempClickMap();
                break;
            case HOVER:
                break;
            case NOTHING:
                break;
            default:
                break;
            }
            this.repaint();
        }
    }

    @Override
    public void actionPerformed(ActionEvent arg0) {
    }

    @Override
    public void mouseDragged(MouseEvent arg0) {
        // TODO Auto-generated method stub
    }

    @Override
    public void mouseMoved(MouseEvent ev) {
        this.resetTempClickMap();
        if (this.isEnabled()) {
            DeskCoordinate dc = this.decodeClick(ev.getX(), ev.getY());
            this.tempClickMap[dc.getX()][dc.getY()].type = ClickableType.HOVER;
            this.repaint();
        }
    }

    // endregion Listeners
    public Color colorLighten(Color c, float ratio, boolean grayscaled) {
        if ((ratio > 1) || (ratio < 0)) {
            ratio = 1;
        }
        int r = Math.round(255 - ratio * c.getRed());
        int g1 = Math.round(255 - ratio * c.getGreen());
        int b = Math.round(255 - ratio * c.getBlue());
        if (grayscaled) {
            r = (r + g1 + b) / 3;
            g1 = r;
            b = r;
        }
        return new Color(r, g1, b);
    }

    @Override
    public void setEnabled(boolean enabled) {
        super.setEnabled(enabled);
        System.out.println("a");
        this.repaint();
    }

    public void setFromDesk(Desk d) {
        // TODO: this is temporary should be
        // BoardDesk = d.duplicate();
        this.BoardDesk = d;
        this.refresh(null, true);
    }

    public void refresh(FigureColor fc, boolean paintMoves) {
        this.gameMoves = null;
        if (fc != null) {
            this.gameMoves = this.BoardDesk.getAllMoves(fc);
        }
        if (paintMoves) {
            this.setMainClickMap(this.gameMoves, null, true);

        } else {
            this.clearMainClickMap();
        }
        this.resetTempClickMap();
        this.repaint();
    };

    public DeskCoordinate decodeClick(int x, int y) {
        DeskCoordinate dc = new DeskCoordinate('a', 1);
        int fieldWidth = (this.getWidth() - 2 * borderWidth) / this.dim;
        dc.setX((y - borderWidth) / fieldWidth);
        dc.setX(this.dim - dc.getX() - 1);
        dc.setY((x - borderWidth) / fieldWidth);
        if (dc.getX() >= this.dim) {
            dc.setX(this.dim - 1);
        }
        if (dc.getY() >= this.dim) {
            dc.setY(this.dim - 1);
        }
        if (dc.getX() < 0) {
            dc.setX(0);
        }
        if (dc.getY() < 0) {
            dc.setY(0);
        }
        return dc;
    }

    public void paintField(Graphics g, int row, int col, Color color) {
        int width = (this.getWidth() - 2 * borderWidth) / this.dim;
        int x = col * width + borderWidth;
        int y = (this.dim - row - 1) * width + borderWidth;

        if ((row + col) % 2 == 0) {
            switch (this.tempClickMap[row][col].type) {
            case DESTINATION:
                g.setColor(Color.orange);
                break;
            case FIGURE:
                g.setColor(Color.green);
                break;
            case HOVER:
                g.setColor(Color.lightGray);
                break;
            case NOTHING:
                g.setColor(Color.gray);
                break;
            default:
                break;
            }
            if (!this.isEnabled()) {
                g.setColor(this.colorLighten(g.getColor(), 0.4f, false));
            }
            g.fillRect(x, y, width, width);
            if (this.BoardDesk != null) {
                Figure f = this.BoardDesk.getFigureAt(Desk.unmapColumn(col), Desk.unmapRow(row));
                if (f instanceof Piece) {
                    if (f.getColor() == FigureColor.BLACK) {
                        g.drawImage(this.iPieceBlack, x, y, width, width, null);
                    } else {
                        g.drawImage(this.iPieceWhite, x, y, width, width, null);
                    }
                } else if (f instanceof Queen) {
                    if (f.getColor() == FigureColor.BLACK) {
                        g.drawImage(this.iKingBlack, x, y, width, width, null);
                    } else {
                        g.drawImage(this.iKingWhite, x, y, width, width, null);
                    }
                }

                /*
                 * if (row <= this.fullRows) { g.drawImage(this.iKingWhite, x,
                 * y, width, width, null); } if (row > this.dim - this.fullRows)
                 * { g.drawImage(this.iPieceBlack, x, y, width, width, null); }
                 */
            }
        } else {
            g.setColor(Color.WHITE);
            g.fillRect(x, y, width, width);
        }
    }

    @Override
    public void paint(Graphics g) {
        super.paint(g);
        int width = this.getWidth();
        int bw = Board.borderWidth;
        final float fs = 14f;
        Font font;
        font = g.getFont().deriveFont(Font.BOLD, fs);
        if (this.isEnabled()) {
            g.drawImage(this.iBackground, 0, 0, width, width, null);
        } else {
            g.drawImage(this.iBackgroundGray, 0, 0, width, width, null);
        }
        for (int row = 0; row < this.dim; row++) {
            g.setFont(font);
            g.setColor(Color.LIGHT_GRAY);
            if (!this.isEnabled()) {
                g.setColor(this.colorLighten(g.getColor(), 0.4f, false));
            }
            g.drawString("" + (this.dim - row), Math.round(fs / 2) - 2,
                    Math.round(bw + (width - 2 * bw) * (0.5f + row) / this.dim));

            for (int col = 0; col < this.dim; col++) {
                if (row == 0) {
                    g.setFont(font);
                    g.setColor(Color.LIGHT_GRAY);
                    if (!this.isEnabled()) {
                        g.setColor(this.colorLighten(g.getColor(), 0.4f, false));
                    }
                    g.drawString(
                            "" + (char) ('A' + col),
                            Math.round(bw - fs / 2 + (width - 2 * Board.borderWidth) * (0.5f + col)
                                    / this.dim), width - Math.round(fs / 2) + 2);
                }
                this.paintField(g, row, col, Color.gray);
            }
        }
    }
}